
#include "gkt_backboard.h"
#include "gkt_debug.h"
#include "gkt_user_defines.h"
#include "gkt_network.h"
#include "gkt_date_time.h"
#include "gkt_rtc.h"
#include "gkt_os.h"

#if defined(GKT_CONFIG_NETWORK_ENABLE) && GKT_CONFIG_NETWORK_ENABLE \
	&& (GKT_BACKBOARD_DRVIC_TUYA == GKT_BACKBOARD_DRVIC)

enum {
	NETWORK_OP_NUKNOW = 0,
	NETWORK_OP_MCU_INFO = 0x01,
	NETWORK_OP_GET_STATUS = 0x1A,
	NETWORK_OP_STATUS = 0x02,
	NETWORK_OP_CONNECT_CONFIG = 0x03,
	NETWORK_OP_CONNECT_CONFIG_SELECTABLE = 0x04,
	NETWORK_OP_REAL_STATUS_UPLOAD = 0x05,
	NETWORK_OP_GET_TIME_LOCAL = 0x06,
	NETWORK_OP_GET_TIME_GMT= 0x10,
	NETWORK_OP_RECORD_STATUS_UPLOAD = 0x08,
	NETWORK_OP_CONTROL_COMMAND = 0x09,
	NETWORK_OP_WIFI_UPGRADE = 0x0a,
	NETWORK_OP_SIGNAL_STRENGTH = 0x0d,
	NETWORK_OP_MCU_UPGRADE_REQ = 0x0c,
	NETWORK_OP_MCU_UPGRADE_START = 0x0d,
	NETWORK_OP_MCU_UPGRADE_DATA_TRANSFER = 0x0e,

	NETWORK_OP_MAX	
};

enum {
	NETWORK_REQ_CONFIG_CONNECT,
	NETWORK_REQ_FIRMWARE_UPGRADE,
	NETWORK_REQ_SELF_TEST,
	NETWORK_REQ_MAX
};

enum {
	NETWORK_COMMON_RSP_STATUS = GKT_BB_APP_PACKET_MINSIZE,
	NETWORK_COMMON_RSP_MAX
};

typedef struct {
	int init_ok;

	uint32_t req_type;
	uint32_t req_time_ms;
	gkt_network_connect_st_e connect_status;
	gkt_soft_timer_t timer_id;
	int sync_time_retry_count;
	uint32_t sync_time_enable;
	gkt_network_mcu_upgrade_data_s upgrade_data;

	gkt_network_notify_fn notify;
} network_bb_s;
static network_bb_s s_network_bb;

#define NETWORK_BB_SYNC_TIME_RETRY_COUNT_MAX 3

static int network_check_req(int req_type)
{
	uint32_t maxtime, req_time_ms;

	gkt_trace("network: req_type(%d - %d), status(%u)\n", 
				s_network_bb.req_type, req_type, 
				s_network_bb.connect_status);

	if (s_network_bb.req_type != NETWORK_REQ_MAX) {
		if (NETWORK_REQ_CONFIG_CONNECT == s_network_bb.req_type) {
			if (GKT_NETWORK_CONNECT_ST_CONNECTED == s_network_bb.connect_status)
				return GKT_EALREADY;
			
			maxtime = GKT_NETWORK_CONNECT_TIMEOUT_SEC;
		}
		else if (NETWORK_REQ_FIRMWARE_UPGRADE == s_network_bb.req_type)
			maxtime = GKT_NETWORK_FIRMWARE_UPGRADE_TIMEOUT_SEC;
		else if (NETWORK_REQ_SELF_TEST == s_network_bb.req_type)
			maxtime = GKT_NETWORK_SELF_TEST_TIMEOUT_SEC;
		else
			return GKT_EPARAM;

		maxtime = (maxtime*1000) + 100;

		req_time_ms = gkt_systime_ms();
		gkt_trace("network_check_req: req_time_ms(pre:%u - :now:%u), maxtime(%u)\n", 
				s_network_bb.req_time_ms, req_time_ms, maxtime);
		if ((s_network_bb.req_time_ms < req_time_ms)
			&& ((req_time_ms - s_network_bb.req_time_ms) >= maxtime)) 
		{
			s_network_bb.req_type = NETWORK_REQ_MAX;
			return GKT_SUCCESS;
		}
		else if (s_network_bb.req_type == req_type)
			return GKT_EINPROCESS;
		else
			return GKT_EPERMIT;
	}

	return GKT_SUCCESS;
}

void network_inner_notify(uint32_t type, uint32_t status)
{
	gkt_trace("network_inner_notify: type(%u), status(%u)\n", type, status);
	if (s_network_bb.notify)
		(*s_network_bb.notify)(type, status);
}
void gkt_network_register_notify(gkt_network_notify_fn notify)
{
	s_network_bb.notify = notify;
}

int gkt_network_is_connected(void)
{
	return (GKT_NETWORK_CONNECT_ST_CONNECTED == s_network_bb.connect_status) ? 1 : 0;
}
void gkt_network_set_sync_time_enable(uint32_t sync_time_enable)
{
	s_network_bb.sync_time_enable = sync_time_enable;
}
enum {
	NETWORK_TIME_SYNC_RSP_ZONE = GKT_BB_APP_PACKET_MINSIZE,
	NETWORK_TIME_SYNC_RSP_TIME,
	NETWORK_TIME_SYNC_RSP_MAX = NETWORK_TIME_SYNC_RSP_TIME+4,
};
static void network_set_rtc_time(uint32_t time)
{
	gkt_date_time_s dt;
	int retval;

	if (time) {
		retval = gkt_dt_localtime(&dt, time);
		if (GKT_SUCCESS == retval) {
			gkt_info("y-m-d-h-m  %u:%u:%u_%u:%u", dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute);
			gkt_rtc_set_time(&dt);
		}
	}
}
static void network_time_sync_moudle_notify(int type, 
				const uint8_t *data, int length_retval)
{
	uint32_t time;

	if (!s_network_bb.sync_time_enable)
		return;

	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_TIME_SYNC_RSP_MAX) {
			gkt_error("network_time_sync_moudle_notify: <PEER> data length invalid!\n");
			return;
		}
		time = gkt_fetch_be32(&data[NETWORK_TIME_SYNC_RSP_TIME]); //local time(utc-8)
		gkt_trace("network_time_sync_moudle_notify: <PEER> time(%u)\n",
			time);
		network_set_rtc_time(time);
		//network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_TIME_SYNC, 0);
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_time_sync_moudle_notify: <LOCAL> retval(%d)\n",
			length_retval);
		time = 0;
	}
	else
		return;

}
int gkt_network_time_sync(void)
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	if (!s_network_bb.sync_time_enable)
		return GKT_ENEEDLESS;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_GET_TIME;
	return gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);

}
static void network_sync_time_timer_callback(void *p)
{
	int retval;

	if (!s_network_bb.sync_time_enable)
		return;

	retval = gkt_network_time_sync();
	if (retval != GKT_SUCCESS) {
		if (s_network_bb.sync_time_retry_count < NETWORK_BB_SYNC_TIME_RETRY_COUNT_MAX) {
			gkt_soft_timer_start(s_network_bb.timer_id, 1000);
			s_network_bb.sync_time_retry_count++;
		}
	}
	else
		s_network_bb.sync_time_retry_count = 0;
}
static void network_status_modele_notify(int type, const uint8_t *data)
{
	uint8_t status;
	//Whether to proactively notify window ?
	if (GKT_BB_NOTIFY_PEER == type) {
		status = data[GKT_BB_APP_PACKET_MINSIZE];
		if (status >= GKT_NETWORK_CONNECT_ST_MAX) {
			gkt_error("network_notify:  <PEER> ERROR - status(%u)\n", status);
			return;
		}
		gkt_trace("network_status_modele_notify: <PEER> connect status(%u)\n", status);
		s_network_bb.connect_status = status;

		if (status == GKT_NETWORK_CONNECT_ST_CONNECTED) {
			if (s_network_bb.sync_time_enable) {
				if (GKT_SUCCESS != gkt_soft_timer_start(s_network_bb.timer_id, 1)) {
					gkt_error("network_bb: timer start failed\n");
					gkt_soft_timer_stop(s_network_bb.timer_id);
				}
			}
		}
	}
}
int gkt_network_get_status_request()
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];

	gkt_trace("network_get_status enter: status(%u)\n", s_network_bb.connect_status);

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_GET_STATUS;
	return gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);
}
uint32_t gkt_network_get_status()
{
	return s_network_bb.connect_status;
}

static void network_connect_module_notify(int type, 
				const uint8_t *data, int length_retval)
{
	uint8_t bb_status;
	uint8_t notify_status;

	if (s_network_bb.req_type != NETWORK_REQ_CONFIG_CONNECT) {
		gkt_error("network_connect_module_notify: <%d> not connect req!\n", 
				s_network_bb.req_type);
		return;
	}
	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_COMMON_RSP_STATUS) {
			gkt_error("network_connect_module_notify: <PEER> data length invalid!\n");
			return;
		}

		bb_status = data[NETWORK_COMMON_RSP_STATUS];
		gkt_trace("network_connect_module_notify: <PEER> bb_status(%u)\n",
			bb_status);

		if ((GKT_BB_STATUS_START == bb_status)
			|| (GKT_BB_STATUS_INPROCESS == bb_status))
		{
			notify_status = GKT_NETWORK_RUNNING_ST_CONNECTING;
		}
		else if ((GKT_BB_STATUS_SUCCESS == bb_status)
			|| (GKT_BB_STATUS_COMPLETE == bb_status)) 
		{
			notify_status = GKT_NETWORK_RUNNING_ST_CONNECTED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else if (GKT_BB_STATUS_NEEDLESS == bb_status) {
			notify_status = GKT_NETWORK_RUNNING_ST_CONNECT_CANCELED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else if (bb_status >= GKT_BB_STATUS_ERR_BASE) {
			notify_status = GKT_NETWORK_RUNNING_ST_CONNECT_FAILED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else
			return;
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_connect_module_notify: <LOCAL> retval(%d)\n",
			length_retval);
		notify_status = GKT_NETWORK_RUNNING_ST_CONNECT_FAILED;
		s_network_bb.req_type = NETWORK_REQ_MAX;
	}
	else
		return;

	network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_RUNNING_STATUS, notify_status);
	
}
int gkt_network_connect()
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];
	int retval;

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_POWER_DONW == s_network_bb.connect_status)
		return GKT_EPERMIT;

	retval = network_check_req(NETWORK_REQ_CONFIG_CONNECT);
	if (GKT_SUCCESS == retval) {
		s_network_bb.req_type = NETWORK_REQ_CONFIG_CONNECT;
		s_network_bb.req_time_ms = gkt_systime_ms();

		data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
		data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_CONNECT_CONFIG;
		retval = gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);
		if ((GKT_SUCCESS != retval) && (GKT_EINPROCESS != retval)) {
			s_network_bb.req_time_ms = 0;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
	}
	return retval;

}

static void network_connect_cancel_module_notify(int type,
				const uint8_t *data, int length_retval)
{
	uint8_t bb_status;
	uint8_t notify_status;

	if (s_network_bb.req_type != NETWORK_REQ_CONFIG_CONNECT) {
		gkt_error("network_connect_cancel_module_notify: <%d> not connect req!\n",
				s_network_bb.req_type);
		return;
	}
	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_COMMON_RSP_STATUS) {
			gkt_error("network_connect_cancel_module_notify: <PEER> data length invalid!\n");
			return;
		}

		bb_status = data[NETWORK_COMMON_RSP_STATUS];
		gkt_trace("network_connect_cancel_module_notify: <PEER> bb_status(%u)\n",
			bb_status);

		if ((GKT_BB_STATUS_SUCCESS == bb_status)
		|| (GKT_BB_STATUS_COMPLETE == bb_status))
		{
			notify_status = GKT_NETWORK_RUNNING_ST_CONNECT_CANCELED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else if (bb_status >= GKT_BB_STATUS_ERR_BASE) {
			if (GKT_BB_STATUS_ERR_FORBID == bb_status)
				notify_status = GKT_NETWORK_RUNNING_ST_CONNECT_CANCEL_FORBID;
			else if (GKT_BB_STATUS_ERR_OPCODE == bb_status)
				return;
			else
				notify_status = GKT_NETWORK_RUNNING_ST_CONNECT_CANCEL_FAILED;
		}
		else
			return;
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_connect_cancel_module_notify: <LOCAL> retval(%d)\n",
			length_retval);
		notify_status = GKT_NETWORK_RUNNING_ST_CONNECT_CANCEL_FAILED;
	}
	else
		return;

	network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_RUNNING_STATUS, notify_status);

}
int gkt_network_connect_cancel(void)
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (NETWORK_REQ_CONFIG_CONNECT != s_network_bb.req_type)
		return GKT_ENOTSTART;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_CONNECT_CANCEL;
	return gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);
}


int gkt_network_reset(void)
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_RESET;
	return gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);
}

void network_firmware_upgrade_module_notify(int type, 
				const uint8_t *data, int length_retval)
{
	uint8_t bb_status;
	uint8_t notify_status;

	if (s_network_bb.req_type != NETWORK_REQ_FIRMWARE_UPGRADE) {
		gkt_error("network_firmware_upgrade_module_notify: <%d> not firmware upgrade req!\n", 
				s_network_bb.req_type);
		return;
	}
	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_COMMON_RSP_STATUS) {
			gkt_error("network_firmware_upgrade_module_notify: <PEER> data length invalid!\n");
			return;
		}

		bb_status = data[NETWORK_COMMON_RSP_STATUS];
		gkt_trace("network_firmware_upgrade_module_notify: <PEER> bb_status(%u)\n",
			bb_status);

		if ((GKT_BB_STATUS_START == bb_status)
			|| (GKT_BB_STATUS_INPROCESS == bb_status))
		{
			notify_status = GKT_NETWORK_RUNNING_ST_UPGRADING;
		}
		else if ((GKT_BB_STATUS_SUCCESS == bb_status)
			|| (GKT_BB_STATUS_COMPLETE == bb_status)) 
		{
			notify_status = GKT_NETWORK_RUNNING_ST_UPGRADED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else if (GKT_BB_STATUS_NEEDLESS == bb_status) {
			notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_CANCELED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else if (bb_status >= GKT_BB_STATUS_ERR_BASE) {
			notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_FAILED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else
			return;
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_firmware_upgrade_module_notify: <LOCAL> retval(%d)\n",
			length_retval);
		notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_FAILED;
		s_network_bb.req_type = NETWORK_REQ_MAX;
	}
	else
		return;

	network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_RUNNING_STATUS, notify_status);
	
}
void network_upgrade_progerss_moudle_notify(int type, const uint8_t *data)
{
	uint8_t progerss;
	if (GKT_BB_NOTIFY_PEER == type) {
		progerss = data[GKT_BB_APP_PACKET_MINSIZE];
		if (progerss > 100) {
			gkt_error("network_notify:  <PEER> ERROR - progerss(%u)\n", progerss);
			return;
		}
		//if (100 == progerss) {
		//do_something(); ?
		//}

		network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_UPGRADE_PROGERSS, progerss);
	}
}
int gkt_network_firmware_upgrade(void)
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];
	int retval;

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	retval = network_check_req(NETWORK_REQ_FIRMWARE_UPGRADE);
	if (GKT_SUCCESS == retval) {
		s_network_bb.req_type = NETWORK_REQ_FIRMWARE_UPGRADE;
		s_network_bb.req_time_ms = gkt_systime_ms();

		data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
		data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_FIRMWARE_UPGRADE;
		retval = gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);
		if ((GKT_SUCCESS != retval) && (GKT_EINPROCESS != retval)) {
			s_network_bb.req_time_ms = 0;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
	}
	return retval;
}

void network_firmware_upgrade_cancel_module_notify(int type,
				const uint8_t *data, int length_retval)
{
	uint8_t bb_status;
	uint8_t notify_status;

	if (s_network_bb.req_type != NETWORK_REQ_FIRMWARE_UPGRADE) {
		gkt_error("network_firmware_upgrade_cancel_module_notify: <%d> not firmware upgrade req!\n", 
				s_network_bb.req_type);
		return;
	}
	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_COMMON_RSP_STATUS) {
			gkt_error("network_firmware_upgrade_cancel_module_notify: <PEER> data length invalid!\n");
			return;
		}

		bb_status = data[NETWORK_COMMON_RSP_STATUS];
		gkt_trace("network_firmware_upgrade_cancel_module_notify: <PEER> bb_status(%u)\n",
			bb_status);

		if ((GKT_BB_STATUS_SUCCESS == bb_status)
		|| (GKT_BB_STATUS_COMPLETE == bb_status))
		{
			notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_CANCELED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else if (bb_status >= GKT_BB_STATUS_ERR_BASE) {
			if (GKT_BB_STATUS_ERR_FORBID == bb_status)
				notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_CANCEL_FORBID;
			else if (GKT_BB_STATUS_ERR_OPCODE == bb_status)
				return;
			else
				notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_CANCEL_FAILED;
		}
		else
			return;
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_firmware_upgrade_module_notify: <LOCAL> retval(%d)\n",
			length_retval);
		notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_CANCEL_FAILED;
	}
	else
		return;

	network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_RUNNING_STATUS, notify_status);

}
int gkt_network_firmware_upgrade_cancel(void)
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (NETWORK_REQ_FIRMWARE_UPGRADE != s_network_bb.req_type)
		return GKT_ENOTSTART;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_FIRMWARE_UPGRADE_CANCEL;
	return gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);
}

void network_self_test_module_notify(int type, 
				const uint8_t *data, int length_retval)
{
	uint8_t bb_status;
	uint8_t notify_status;

	if (s_network_bb.req_type != NETWORK_REQ_SELF_TEST) {
		gkt_error("network_self_test_module_notify: <%d> not self test req!\n", 
				s_network_bb.req_type);
		return;
	}
	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_COMMON_RSP_STATUS) {
			gkt_error("network_self_test_module_notify: <PEER> data length invalid!\n");
			return;
		}

		bb_status = data[NETWORK_COMMON_RSP_STATUS];
		gkt_trace("network_self_test_module_notify: <PEER> bb_status(%u)\n",
			bb_status);

		if ((GKT_BB_STATUS_START == bb_status)
			|| (GKT_BB_STATUS_INPROCESS == bb_status))
		{
			notify_status = GKT_NETWORK_RUNNING_ST_TESTING;
			return;
		}
		else if ((GKT_BB_STATUS_SUCCESS == bb_status)
			|| (GKT_BB_STATUS_COMPLETE == bb_status)) 
		{
			notify_status = GKT_NETWORK_RUNNING_ST_TEST_COMPLETE;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else if (bb_status >= GKT_BB_STATUS_ERR_BASE) {
			notify_status = GKT_NETWORK_RUNNING_ST_TEST_FAILED;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
		else
			return;
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_self_test_module_notify: <LOCAL> retval(%d)\n",
			length_retval);
		notify_status = GKT_NETWORK_RUNNING_ST_TEST_FAILED;
		s_network_bb.req_type = NETWORK_REQ_MAX;
	}
	else
		return;

	network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_RUNNING_STATUS, notify_status);
	
}
int gkt_network_self_test(void)
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];
	int retval;

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	retval = network_check_req(NETWORK_REQ_SELF_TEST);
	if (GKT_SUCCESS == retval) {
		s_network_bb.req_type = NETWORK_REQ_SELF_TEST;
		s_network_bb.req_time_ms = gkt_systime_ms();

		data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
		data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_TEST;
		retval = gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);
		if ((GKT_SUCCESS != retval) && (GKT_EINPROCESS != retval)) {
			s_network_bb.req_time_ms = 0;
			s_network_bb.req_type = NETWORK_REQ_MAX;
		}
	}
	return retval;
}

enum {
	NETWORK_UNLOCK_RECORD_REQ_TYPE = GKT_BB_APP_PACKET_MINSIZE,

	NETWORK_UNLOCK_RECORD_REQ_USER0_TYPE,
	NETWORK_UNLOCK_RECORD_REQ_USER0_EXTEND_TYPE,
	NETWORK_UNLOCK_RECORD_REQ_USER0_INDEX_HIGH,
	NETWORK_UNLOCK_RECORD_REQ_USER0_INDEX_LOW,
	NETWORK_UNLOCK_RECORD_REQ_USER0_MAX,
	
	NETWORK_UNLOCK_RECORD_REQ_USER1_TYPE = NETWORK_UNLOCK_RECORD_REQ_USER0_MAX,
	NETWORK_UNLOCK_RECORD_REQ_USER1_EXTEND_TYPE,
	NETWORK_UNLOCK_RECORD_REQ_USER1_INDEX_HIGH,
	NETWORK_UNLOCK_RECORD_REQ_USER1_INDEX_LOW,
	NETWORK_UNLOCK_RECORD_REQ_MAX,
};
int gkt_network_unlock_record(gkt_network_unlock_type_e type,
				uint32_t user_id_nums, uint32_t *user_ids)
{
	static uint8_t data[NETWORK_UNLOCK_RECORD_REQ_MAX];//Larger than 6 bytes cannot use stack area
	uint32_t data_len;

	for (data_len=0; data_len<NETWORK_UNLOCK_RECORD_REQ_MAX; data_len++)
		data[data_len] = 0x00;

	gkt_unused(user_id_nums);

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	gkt_trace("gkt_network_unlock_record: auth - type - index, (%u, %u, %u)\n",
		GKT_USER_AUTH(user_ids[0]), GKT_USER_TYPE(user_ids[0]), GKT_USER_INDEX(user_ids[0]));
	if ((type < GKT_NETWORK_UNLOCK_TYPE_MAX) && (NULL != user_ids)) {
		data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
		data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_UNLOCK_RECORD;
		data[NETWORK_UNLOCK_RECORD_REQ_TYPE] = (uint8_t)type;
		data[NETWORK_UNLOCK_RECORD_REQ_USER0_TYPE] = 
			(uint8_t)((GKT_USER_AUTH(user_ids[0]) << 4) | GKT_USER_TYPE(user_ids[0]));

		if (GKT_NETWORK_UNLOCK_TYPE_KEY == type)
			data[NETWORK_UNLOCK_RECORD_REQ_USER0_EXTEND_TYPE] = 0xFF;
		else if (GKT_NETWORK_UNLOCK_TYPE_VERIFY == type)
			data[NETWORK_UNLOCK_RECORD_REQ_USER0_EXTEND_TYPE] = GKT_USER_TYPE_EXTEND(user_ids[0]);
		else if (GKT_NETWORK_UNLOCK_TYPE_REMOTE == type)
			data[NETWORK_UNLOCK_RECORD_REQ_USER0_EXTEND_TYPE] = 0x00;

		gkt_store_be16(&data[NETWORK_UNLOCK_RECORD_REQ_USER0_INDEX_HIGH], GKT_USER_INDEX(user_ids[0]));
		if (user_id_nums > 1) {
			data[NETWORK_UNLOCK_RECORD_REQ_USER1_TYPE] = 
			(uint8_t)((GKT_USER_AUTH(user_ids[1]) << 4) | GKT_USER_TYPE(user_ids[1]));

			if (GKT_NETWORK_UNLOCK_TYPE_KEY == type)
				data[NETWORK_UNLOCK_RECORD_REQ_USER1_EXTEND_TYPE] = 0xFF;
			else if (GKT_NETWORK_UNLOCK_TYPE_VERIFY == type)
				data[NETWORK_UNLOCK_RECORD_REQ_USER1_EXTEND_TYPE] = GKT_USER_TYPE_EXTEND(user_ids[1]);
			else if (GKT_NETWORK_UNLOCK_TYPE_REMOTE == type)
				data[NETWORK_UNLOCK_RECORD_REQ_USER1_EXTEND_TYPE] = 0x00;

			gkt_store_be16(&data[NETWORK_UNLOCK_RECORD_REQ_USER1_INDEX_HIGH], GKT_USER_INDEX(user_ids[1]));

			data_len = NETWORK_UNLOCK_RECORD_REQ_MAX;
		}
		else
			data_len = NETWORK_UNLOCK_RECORD_REQ_USER0_MAX;

		return gkt_backboard_send_data(data, data_len);
	}
	return GKT_EPARAM;
	
}

enum {
	NETWORK_REMOTE_UNLOCK_RSP_USERID_HIGH = GKT_BB_APP_PACKET_MINSIZE,
	NETWORK_REMOTE_UNLOCK_RSP_USERID_LOW,
	NETWORK_REMOTE_UNLOCK_RSP_MAX
};
static void network_remote_unlock_moudle_notify(int type, 

				const uint8_t *data, int length_retval)
{
	uint32_t userid;

	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_REMOTE_UNLOCK_RSP_MAX) {
			gkt_error("network_remote_unlock_moudle_notify: <PEER> data length invalid!\n");
			return;
		}
		userid = gkt_fetch_be16(&data[NETWORK_REMOTE_UNLOCK_RSP_USERID_HIGH]);
		gkt_trace("network_remote_unlock_moudle_notify: <PEER> userid(%u)\n",
			userid);
		network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_REMOTE_UNLOCK, userid);
	}
}

enum {
	NETWORK_REMOTO_UNLOCK_REQ_TYPE = GKT_BB_APP_PACKET_MINSIZE,
	NETWORK_REMOTO_UNLOCK_REQ_MAX,
};
int gkt_network_remote_unlock_request(int action)
{
	uint8_t data[NETWORK_REMOTO_UNLOCK_REQ_MAX];

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_REMOTE_UNLOCK_REQ;
	data[NETWORK_REMOTO_UNLOCK_REQ_TYPE] = (uint8_t)action;
	return gkt_backboard_send_data(data, NETWORK_REMOTO_UNLOCK_REQ_MAX);
}

enum {
	NETWORK_MESSAGE_UPLOAD_TYPE = GKT_BB_APP_PACKET_MINSIZE,
	NETWORK_MESSAGE_UPLOAD_MAX,
};
int gkt_network_message_upload(gkt_network_message_type_e type)
{
	uint8_t data[NETWORK_MESSAGE_UPLOAD_MAX];

	if (type >= GKT_NETWORK_MESSAGE_TYPE_MAX)
		return GKT_EPARAM;

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_MESSAGE_UPLOAD;
	data[NETWORK_MESSAGE_UPLOAD_TYPE] = (uint8_t)type;
	return gkt_backboard_send_data(data, NETWORK_MESSAGE_UPLOAD_MAX);
}

void network_mcu_upgrade_req_module_notify(int type, 
				const uint8_t *data, int length_retval)
{
	uint8_t bb_status;
	uint8_t notify_status;

	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_COMMON_RSP_STATUS) {
			gkt_error("network_mcu_upgrade_module_notify: <PEER> data length invalid!\n");
			return;
		}

		bb_status = data[NETWORK_COMMON_RSP_STATUS];
		gkt_trace("network_self_test_module_notify: <PEER> bb_status(%u)\n",
			bb_status);

		if ((GKT_BB_STATUS_START == bb_status)
			|| (GKT_BB_STATUS_INPROCESS == bb_status))
		{
			notify_status = GKT_NETWORK_RUNNING_ST_UPGRADING;
		}
		else if ((GKT_BB_STATUS_SUCCESS == bb_status)
			|| (GKT_BB_STATUS_COMPLETE == bb_status)) 
		{
			notify_status = GKT_NETWORK_RUNNING_ST_UPGRADED;
		}
		else if (bb_status >= GKT_BB_STATUS_ERR_BASE) {
			notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_FAILED;
		}
		else
			return;
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_mcu_upgrade_req_module_notify: <LOCAL> retval(%d)\n",
			length_retval);
		notify_status = GKT_NETWORK_RUNNING_ST_UPGRADE_FAILED;
	}
	else
		return;

	network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_RUNNING_STATUS, notify_status);

}

enum {
	NETWORK_MCU_UPGRADE_PRODUCT_ID = GKT_BB_APP_PACKET_MINSIZE,
	NETWORK_MCU_UPGRADE_SW_VERSION = NETWORK_MCU_UPGRADE_PRODUCT_ID + 8,

	NETWORK_MCU_UPGRADE_REQ_MAX = NETWORK_MCU_UPGRADE_SW_VERSION + 4,
};
int gkt_network_mcu_upgrade_request(
				const uint8_t product_id[], uint32_t sw_version)
{
	static uint8_t data[NETWORK_MCU_UPGRADE_REQ_MAX];
	int i;

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	if (NULL == product_id)
		return GKT_EPARAM;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_MCU_UPGRADE_REQ;
	for (i=0; i<8; i++)
		&data[NETWORK_MCU_UPGRADE_PRODUCT_ID+i] = product_id[i];
	gkt_store_be32(&data[NETWORK_MCU_UPGRADE_SW_VERSION], sw_version);

	return gkt_backboard_send_data(data, NETWORK_MCU_UPGRADE_REQ_MAX);
}
enum {
	NETWORK_MCU_UPGRADE_FILE_OFFSET = GKT_BB_APP_PACKET_MINSIZE,
	NETWORK_MCU_UPGRADE_FILE_DATA_SIZE = NETWORK_MCU_UPGRADE_FILE_OFFSET + 4,
	NETWORK_MCU_UPGRADE_FILE_DATA,
};
void network_mcu_upgrade_data_transfer_module_notify(int type, 
				const uint8_t *data, int length_retval)
{
	int i;

	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_MCU_UPGRADE_FILE_DATA) {
			gkt_error("network_mcu_upgrade_data_transfer_module_notify: <PEER> data length invalid!\n");
			return;
		}
		if (0 != s_network_bb.upgrade_data.data_size ||
			0 != s_network_bb.upgrade_data.offset)
		{
			gkt_error("network_mcu_upgrade_data_transfer_module_notify: No reply to confirmation package!\n");
			return;
		}
		s_network_bb.upgrade_data.offset = gkt_fetch_be32(&data[NETWORK_MCU_UPGRADE_FILE_OFFSET]);
		s_network_bb.upgrade_data.data_size = gkt_fetch_be32(&data[NETWORK_MCU_UPGRADE_FILE_DATA_SIZE]);
		for (i=0; i<s_network_bb.upgrade_data.data_size; i++)
			s_network_bb.upgrade_data.data_buf[i] = data[NETWORK_MCU_UPGRADE_FILE_DATA+i];

		gkt_info("network_mcu_upgrade_start_module_notify: <PEER> offset(%u), data_size(%u)\n",
			s_network_bb.upgrade_data.offset, s_network_bb.upgrade_data.data_size);
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_mcu_upgrade_data_transfer_module_notify: <LOCAL> retval(%d)\n",
			length_retval);
		return;
	}
	else
		return;

	network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_MCU_UPGRADE_DATA, (uint32_t)&s_network_bb.upgrade_data);

}
int gkt_network_mcu_upgrade_data_transfer_confirm()
{
	uint8_t data[NETWORK_COMMON_RSP_MAX];

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_MCU_UPGRADE_START;
	data[NETWORK_COMMON_RSP_STATUS] = GKT_BB_STATUS_SUCCESS;//后续可删除该字段

	return gkt_backboard_send_data(data, NETWORK_COMMON_RSP_MAX);
}

enum {
	NETWORK_MCU_UPGRADE_FILE_SIZE = GKT_BB_APP_PACKET_MINSIZE + 4,
	NETWORK_MCU_UPGRADE_START_MAX,
};
void network_mcu_upgrade_start_module_notify(int type, 
				const uint8_t *data, int length_retval)
{
	uint32_t guf_total_size;

	if (GKT_BB_NOTIFY_PEER == type) {
		if (length_retval < NETWORK_MCU_UPGRADE_FILE_SIZE) {
			gkt_error("network_mcu_upgrade_start_module_notify: <PEER> data length invalid!\n");
			return;
		}
		guf_total_size = gkt_fetch_be32(&data[GKT_BB_APP_PACKET_MINSIZE]);

		gkt_info("network_mcu_upgrade_start_module_notify: <PEER> guf_total_size(%u)\n",
			guf_total_size);
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_error("network_mcu_upgrade_start_module_notify: <LOCAL> retval(%d)\n",
			length_retval);
		guf_total_size = 0;
	}
	else
		return;

	network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_MCU_UPGRADE_START, guf_total_size);

}

enum {
	NETWORK_MCU_UPGRADE_START_STATUS = GKT_BB_APP_PACKET_MINSIZE,
	NETWORK_MCU_UPGRADE_PACKET_SIZE,

	NETWORK_MCU_UPGRADE_START_MAX = NETWORK_MCU_UPGRADE_PACKET_SIZE+2,
};
int gkt_network_mcu_upgrade_start(uint16_t packet_size)
{
	uint8_t data[NETWORK_MCU_UPGRADE_START_MAX];

	if (!s_network_bb.init_ok)
		return GKT_ENOTINIT;

	if (GKT_NETWORK_CONNECT_ST_CONNECTED != s_network_bb.connect_status)
		return GKT_EPERMIT;

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_NETWORK;
	data[GKT_BB_APP_PACKET_OPCODE] = NETWORK_OP_MCU_UPGRADE_START;
	data[NETWORK_MCU_UPGRADE_START_STATUS] = GKT_BB_STATUS_SUCCESS;//后续可删除该字段
	gkt_store_be16(&data[NETWORK_MCU_UPGRADE_PACKET_SIZE], packet_size);

	return gkt_backboard_send_data(data, NETWORK_MCU_UPGRADE_START_MAX);
}

static void network_module_notify(int type, 

				const uint8_t *data, int length_retval)
{
	uint8_t opcode, bb_status;

	opcode = data[GKT_BB_APP_PACKET_OPCODE];
	gkt_trace("network_notify: type(%d), opcode(%u), length(%d)\n",
		type, opcode, length_retval);

	if (NETWORK_OP_STATUS == opcode)
		network_status_modele_notify(type, data);
	else if (NETWORK_OP_CONNECT_CONFIG == opcode)
		network_connect_module_notify(type, data, length_retval);
	else if (NETWORK_OP_CONNECT_CANCEL == opcode)
		network_connect_cancel_module_notify(type, data, length_retval);
	else if (NETWORK_OP_TIME == opcode)
		network_time_sync_moudle_notify(type, data, length_retval);
	else if (NETWORK_OP_FIRMWARE_UPGRADE == opcode)
		network_firmware_upgrade_module_notify(type, data, length_retval);
	else if (NETWORK_OP_FIRMWARE_UPGRADE_CANCEL == opcode)
		network_firmware_upgrade_cancel_module_notify(type, data, length_retval);
	else if (NETWORK_OP_UPGRADE_PROGRESS == opcode)
		network_upgrade_progerss_moudle_notify(type, data);
	else if (NETWORK_OP_REMOTE_UNLOCK_RSP == opcode)
		network_remote_unlock_moudle_notify(type, data, length_retval);
	else if (NETWORK_OP_TEST == opcode)
		network_self_test_module_notify(type, data, length_retval);
	else if (NETWORK_OP_MCU_UPGRADE_REQ == opcode)
		network_mcu_upgrade_req_module_notify(type, data, length_retval);
	else if (NETWORK_OP_MCU_UPGRADE_START == opcode)
		network_mcu_upgrade_start_module_notify(type, data, length_retval);
	else if (NETWORK_OP_MCU_UPGRADE_DATA_TRANSFER == opcode)
		network_mcu_upgrade_data_transfer_module_notify(type, data, length_retval);
	else {
		if (GKT_BB_NOTIFY_PEER == type) {
			if (length_retval < NETWORK_COMMON_RSP_STATUS)
				return;
			bb_status = data[NETWORK_COMMON_RSP_STATUS];
			gkt_trace("network_notify: <PEER> bb_status(%u)\n", bb_status);

			if ((GKT_BB_STATUS_SUCCESS == bb_status) || (GKT_BB_STATUS_COMPLETE == bb_status))
				length_retval = GKT_SUCCESS;
			else if (bb_status >= GKT_BB_STATUS_ERR_BASE) {
				gkt_error("network_notify: <PEER> ERROR - bb_status(%u)\n", bb_status);
				length_retval = GKT_ELOWLEVEL;
			}
			else
				return;
		}
		else if (length_retval < GKT_SUCCESS) {	/* local */
			gkt_error("network_notify: <LOCAL> opcode(%u) failed %d\n",
				opcode, length_retval);
		}
		else
			return;

		network_inner_notify(GKT_NETWORK_NOTIFY_TYPE_COMMON_STATUS, (uint32_t)length_retval);
	}
}

int gkt_network_init(void)
{
	s_network_bb.init_ok = 0;
	s_network_bb.connect_status = GKT_NETWORK_CONNECT_ST_CONNECTED;
	s_network_bb.req_time_ms = 0;
	s_network_bb.notify = NULL;
	s_network_bb.req_type = NETWORK_REQ_MAX;
	s_network_bb.sync_time_retry_count = 0;
	s_network_bb.sync_time_enable = 1;
	s_network_bb.upgrade_data.offset = 0;
	s_network_bb.upgrade_data.data_size = 0;
	memset(s_network_bb.upgrade_data.data_buf, 0, GKT_GUF_PACKET_SIZE_MAX);	

	s_network_bb.timer_id = gkt_soft_timer_create(GKT_SOFT_TIMER_ONCE, network_sync_time_timer_callback, NULL);
	if (!s_network_bb.timer_id) {
			gkt_error("network_bb: create soft timer failed!\n");
			return GKT_ECREATE;
	}

	gkt_backboard_register_module(GKT_BB_MODULE_NETWORK,
			NETWORK_OP_MAX, network_module_notify);

	s_network_bb.init_ok = 1;

	return GKT_SUCCESS;
}

#endif

